<!DOCTYPE html>
<html>
 
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue数据双向绑定</title>
</head>
<body>
    <input type="text" id="inp1">
    <span id="childSpan1" style="background-color: pink;"></span>
    <input type="text" id="inp2">
</body>
 
</html>
 
<script>
    /**
       * @description: 发布者
       * @param {*}
       * @return {*}
       */
    class Publisher {
        constructor() {
            this.watcherList = []; // 订阅者列表
        }
        // 添加订阅者
        addWatcher(Sub){
           const isHas =  this.watcherList.includes(Sub);
           if(isHas) return
           this.watcherList.push(Sub);
        }

        // 删除订阅
        removeWatcher(Sub){
            this.watcherList = this.watcherList.filter(item=>item!=Sub)
        }

        // 消息通知 
        notify() {
            this.watcherList.forEach(item=>{
                console.log('第2步,接到数据更新后--，更新订阅者，notfiy',item)
                // 订阅者更新
                item.updated();
            })
        }
 
    }
 
    /**
    * @description: 订阅者 Subscriber  Observer
    * @param {*}  name 订阅者名字
    * @return {*}
    */
    class Watcher {
        constructor(name) {
            this.name = name;
        }
        updated() {
            console.log(`第3步：实际更新--${this.name}要进行更新`);
        }
    }
 
    // 创建发布者实例
   var dataAttr1 = new Publisher();
   // 创建第2个发布者实例
   var dataAttr2 = new Publisher();

   // 创建一个订阅者
   var view1 = new Watcher('订阅者组件1');
   // 创建第2个订阅者
   var view2 = new Watcher('订阅者组件2');
    
   // 第一个发布者 添加1个订阅者
   dataAttr1.addWatcher(view1);

   // 第二个发布者 添加2个订阅者
   dataAttr2.addWatcher(view1);
   dataAttr2.addWatcher(view2);

    //原始对象
    var data ={dataAttr1:null, dataAttr2:null};
    // 对像深拷贝
    var definePropertyData = JSON.parse(JSON.stringify(data))//{dataAttr1:null, dataAttr2:null};
    var domText = document.querySelector("#childSpan1");
    Object.keys(definePropertyData).forEach((key)=>{
        Object.defineProperty(definePropertyData,key,{
            get(){
                console.log('get value',key)
                return data[key]
            },
            set(newVal){
                data[key] = newVal;
                console.log(`第1步：劫持数据--，set设置新的value${newVal}`);
                domText.innerHTML = newVal;
                //劫持数据后 发送通知
                window[key].notify();
            }
        })
    })

    var inp1 = document.querySelector('#inp1');
    var inp2 = document.querySelector('#inp2');
    inp1.addEventListener('input', function (e) {
        // 监听文本框里面的值 获取最新的值, 给data的dataAttr1属性赋值，进而触发该属性的set方法
        // 从视图层到数据层的绑定
        definePropertyData.dataAttr1 = e.target.value;
    });
    inp2.addEventListener('input', function (e) {
        definePropertyData.dataAttr2 = e.target.value;
    });
 
</script>
 
</html>